package com.kylin.core.user.event.repository;

import com.kylin.dal.entity.user.QUserAddressEntry;
import com.kylin.dal.entity.user.UserAddressEntry;
import com.kylin.dal.entity.user.UserAddressRepository;
import com.kylin.domain.user.command.*;
import com.kylin.shared.common.consts.Constants;
import com.kylin.shared.enums.YesNoEnum;
import com.kylin.shared.utils.MappingTools;
import com.querydsl.core.QueryResults;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.persistence.EntityManager;
import java.util.Objects;

/**
 * 收货地址信息处理类
 * @author Damon S.
 * @version v1.0.1
 * @date 2020年12月29日 19:25
 */
@Component
public class AddressDataHandler {

    private final JPAQueryFactory addressQueryFactory;
    private final QUserAddressEntry qUserAddressEntry;
    private final UserAddressRepository addressRepository;


    public AddressDataHandler(@Qualifier("kylinArtworkEntityManager")
                                      EntityManager entityManager,
                              UserAddressRepository addressRepository) {
        this.addressQueryFactory = new JPAQueryFactory(entityManager);
        this.qUserAddressEntry = QUserAddressEntry.userAddressEntry;

        this.addressRepository = addressRepository;
    }

    public QueryResults<UserAddressEntry> findUserAddress(QueryUserAddressCommand command) {
        return this.addressQueryFactory.selectFrom(qUserAddressEntry)
                .where(qUserAddressEntry.removed.eq(YesNoEnum.N.getCode())
                        .and(qUserAddressEntry.userId.eq(command.getUserId()))
                ).limit(command.getLimit())
                .offset(command.getOffset() - Constants.LONG_ONE)
                .fetchResults();
    }

    public UserAddressEntry findUserAddressById(Long addressId) {
        return this.addressQueryFactory.selectFrom(qUserAddressEntry)
                .where(qUserAddressEntry.id.eq(addressId))
                .fetchOne();
    }

    public UserAddressEntry findUserAddressDefault(Long userId) {
         return this.addressQueryFactory.selectFrom(qUserAddressEntry)
                .where(qUserAddressEntry.defaulted.eq(YesNoEnum.Y.getCode())
                        .and(qUserAddressEntry.userId.eq(userId))
                        .and(qUserAddressEntry.removed.eq(YesNoEnum.N.getCode()))
                ).fetchOne();
    }

    public UserAddressEntry checkUserAddress(CreateUserAddressCommand command) {
        return this.addressQueryFactory.selectFrom(qUserAddressEntry)
                .where(qUserAddressEntry.userId.eq(command.getUserId())
                        .and(qUserAddressEntry.consignee.eq(command.getConsignee()))
                        .and(qUserAddressEntry.phone.eq(command.getPhone()))
                        .and(qUserAddressEntry.province.eq(command.getProvince()))
                        .and(qUserAddressEntry.city.eq(command.getCity()))
                        .and(qUserAddressEntry.county.eq(command.getCounty()))
                        .and(qUserAddressEntry.address.eq(command.getAddress()))
                        .and(qUserAddressEntry.postcode.eq(command.getPostcode()))
                ).fetchOne();
    }

    public UserAddressEntry addUserAddress(CreateUserAddressCommand command) {
        boolean defaultAddressExists = Constants.LONG_ZERO < this.addressQueryFactory.selectFrom(qUserAddressEntry)
                .where(qUserAddressEntry.removed.eq(YesNoEnum.N.getCode())
                        .and(qUserAddressEntry.userId.eq(command.getUserId()))
                        .and(qUserAddressEntry.defaulted.eq(YesNoEnum.Y.getCode()))
                ).fetchCount();
        UserAddressEntry entry = UserAddressEntry.builder()
                .userId(command.getUserId())
                .consignee(command.getConsignee())
                .phone(command.getPhone())
                .postcode(command.getPostcode())
                .province(command.getProvince())
                .city(command.getCity())
                .county(command.getCounty())
                .defaulted(defaultAddressExists ? YesNoEnum.N.getCode() : YesNoEnum.Y.getCode())
                .removed(YesNoEnum.N.getCode())
                .address(command.getAddress())
                .createdAt(MappingTools.toCurrentEpochSecond())
                .createdBy(command.getCreatedBy())
                .updatedAt(Constants.LONG_MINUS_ONE)
                .updatedBy(Constants.LONG_MINUS_ONE)
                .removedAt(Constants.LONG_MINUS_ONE)
                .removedBy(Constants.LONG_MINUS_ONE)
                .build();
        return addressRepository.saveAndFlush(entry);
    }

    public boolean setDefaultAddress(DefaultUserAddressCommand command) {
        this.addressQueryFactory.update(qUserAddressEntry)
                .set(qUserAddressEntry.defaulted, YesNoEnum.N.getCode())
                .set(qUserAddressEntry.updatedBy, command.getUpdatedBy())
                .set(qUserAddressEntry.updatedAt, command.getUpdatedAt())
                .where(qUserAddressEntry.defaulted.eq(YesNoEnum.Y.getCode())
                        .and(qUserAddressEntry.userId.eq(command.getUserId()))
                ).execute();
        long effectedRowCount = addressQueryFactory.update(qUserAddressEntry)
                .set(qUserAddressEntry.defaulted, YesNoEnum.Y.getCode())
                .set(qUserAddressEntry.updatedBy, command.getUpdatedBy())
                .set(qUserAddressEntry.updatedAt, command.getUpdatedAt())
                .where(qUserAddressEntry.userId.eq(command.getUserId())
                        .and(qUserAddressEntry.id.eq(command.getAddressId()))
                ).execute();
        return Objects.equals(Constants.LONG_ONE, effectedRowCount);
    }

    public boolean removeUserAddress(RemoveUserAddressCommand command) {
        return Objects.equals(Constants.LONG_ONE, this.addressQueryFactory.update(qUserAddressEntry)
                .set(qUserAddressEntry.removed, YesNoEnum.Y.getCode())
                .set(qUserAddressEntry.removedAt, command.getRemovedAt())
                .set(qUserAddressEntry.removedBy, command.getRemovedBy())
                .where(qUserAddressEntry.userId.eq(command.getUserId())
                        .and(qUserAddressEntry.id.eq(command.getAddressId()))
                ).execute()
        );
    }

    public boolean updateUserAddress(UpdateUserAddressCommand command) {
        return Objects.equals(Constants.LONG_ONE, this.addressQueryFactory.update(qUserAddressEntry)
                .set(qUserAddressEntry.address, command.getAddress())
                .set(qUserAddressEntry.city, command.getCity())
                .set(qUserAddressEntry.county, command.getCounty())
                .set(qUserAddressEntry.province, command.getProvince())
                .set(qUserAddressEntry.consignee, command.getConsignee())
                .set(qUserAddressEntry.phone, command.getPhone())
                .set(qUserAddressEntry.postcode, command.getPostcode())
                .set(qUserAddressEntry.updatedAt, MappingTools.toCurrentEpochSecond())
                .set(qUserAddressEntry.updatedBy, command.getUpdatedBy())
                .where(qUserAddressEntry.id.eq(command.getAddressId())
                        .and(qUserAddressEntry.userId.eq(command.getUserId()))
                ).execute()
        );
    }
}
